package com.apabi.service.elastic;

import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.queryparser.classic.QueryParserBase;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequest;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchAction;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.WrapperQueryBuilder;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryAction;
import org.elasticsearch.index.reindex.DeleteByQueryRequestBuilder;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.elasticsearch.index.query.QueryBuilders.termQuery;

@Component
public class Elastic {

    private static final Logger LOGGER = LoggerFactory.getLogger(Elastic.class);

    private Client client;

    @Value("${elastic.cluster}")
    private String cluster;

    @Value("${elastic.nodes}")
    private String nodes;

    @PostConstruct
    private void init() throws UnknownHostException {
        Settings settings = Settings.builder()
                .put("cluster.name", cluster).put("client.transport.ping_timeout", "180s").build();
        TransportClient client = new PreBuiltTransportClient(settings);
        String[] arr = nodes.split(",");
        for (String line : arr) {
            if (StringUtils.isBlank(line)) {
                continue;
            }
            line = line.trim();
            String[] temp = line.split(":");
            client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(temp[0]), Integer.valueOf(temp[1])));
            LOGGER.info("add elastic node:" + line);
        }
        this.client = client;
    }

    @PreDestroy
    private void destory() {
        if (client != null) {
            client.close();
        }
    }

    public Client getClient() {
        return this.client;
    }

    public List<AnalyzeResponse.AnalyzeToken> analyze(String index, String analyzer, String text) {
        AnalyzeResponse response =  client.admin().indices().prepareAnalyze(index, QueryParserBase.escape(text)).setAnalyzer(analyzer).execute().actionGet();
        return response.getTokens();
    }

    public CreateIndexResponse createIndex(String index, String query) {
        CreateIndexRequest indexRequest = new CreateIndexRequest(index);
        return client.admin().indices().create(indexRequest.source(query, XContentType.JSON)).actionGet();
    }

    public DeleteIndexResponse deleteIndex(String index) {
        DeleteIndexRequest request = new DeleteIndexRequest(index);
        return client.admin().indices().delete(request).actionGet();
    }

    public IndexResponse index(String index, String type, String id, String source) {
        if(id.equals("_N_")){
            return client.prepareIndex(index, type).setSource(source,XContentType.JSON).execute().actionGet();
        }else{
            return client.prepareIndex(index, type, id).setSource(source,XContentType.JSON).execute().actionGet();
        }
    }

    public PutMappingResponse putMapping(String index, String type, String mapping) {
        PutMappingRequest request = new PutMappingRequest(index).type(type).source(mapping, XContentType.JSON);
        return client.admin().indices().putMapping(request).actionGet();
    }

    public DeleteResponse deleteById(String index, String type, String id) {
        return client.prepareDelete(index, type, id).execute().actionGet();
    }

    public IndicesStatsResponse indices() {
        return this.client.admin().indices().stats(new IndicesStatsRequest().all()).actionGet();
    }

    public void shutdown() {
        if (client != null) {
            client.close();
        }
    }

    public BulkByScrollResponse deleteMapping(String index, String type,String content) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        SearchModule searchModule = new SearchModule(Settings.EMPTY, false, Collections.emptyList());
        try (XContentParser parser = XContentFactory.xContent(XContentType.JSON)
                .createParser(new NamedXContentRegistry(searchModule.getNamedXContents()), content)) {
            searchSourceBuilder.parseXContent(new QueryParseContext(parser));
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
        QueryBuilder queryBuilder = searchSourceBuilder.query();
        DeleteByQueryRequestBuilder deleteByQueryRequestBuilder = DeleteByQueryAction.INSTANCE.newRequestBuilder(client)
                .source(index).filter(QueryBuilders.typeQuery(type)).filter(queryBuilder);
        BulkByScrollResponse response = deleteByQueryRequestBuilder.get();
        return response;
    }

    public SearchResponse search(String index, String type, String content) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        SearchModule searchModule = new SearchModule(Settings.EMPTY, false, Collections.emptyList());
        try (XContentParser parser = XContentFactory.xContent(XContentType.JSON)
                .createParser(new NamedXContentRegistry(searchModule.getNamedXContents()), content)) {
            searchSourceBuilder.parseXContent(new QueryParseContext(parser));
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
        SearchRequestBuilder searchRequestBuilder = new SearchRequestBuilder(client, SearchAction.INSTANCE);
        String[] arr = index.split(",");
        String[] indeices = new String[arr.length];
        int i = 0;
        for (String tmp : arr) {
            if (!StringUtils.isEmpty(tmp)) {
                indeices[i] = tmp.trim();
                i++;
            }
        }
        searchRequestBuilder.setIndices(indeices);
        // searchRequest.setQuery(queryBuilder)
        if (StringUtils.isNoneEmpty(type)) {
            List<String> types = new ArrayList<>();
            for(String t : type.split(",")) {
                if(StringUtils.isNotEmpty(t)) {
                    types.add(t.trim());
                }
            }
            String[] typeArr = new String[types.size()];
            for(i=0;i<types.size();i++) {
                typeArr[i] = types.get(i);
            }
            searchRequestBuilder.setTypes(typeArr);
        }
        SearchResponse searchResponse = searchRequestBuilder.setSource(searchSourceBuilder).execute().actionGet();
        return searchResponse;
    }
}
